{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "0aa3c4c0",
   "metadata": {},
   "source": [
    "## Constructing a Task from C Code\n",
    "\n",
    "Workflows can incorporate functions written in different languages, for example when a compiled C function is used to optimize performance. This example demonstrates how to construct a Lepton from a compiled C function.\n",
    "\n",
    "### Prerequisite\n",
    "\n",
    "Writing a Covalent lepton for a C function presupposes that you have a compiled C function that you want to call from within a Python session. This example creates a simple C program for that purpose.\n",
    "\n",
    "1. Write C source and header files for the program:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "id": "95422edc",
   "metadata": {},
   "outputs": [],
   "source": [
    "c_source = \"\"\"\n",
    "#include \"test.h\"\n",
    "\n",
    "void test_entry(int x, int *y, int *z)\n",
    "{\n",
    "        *y += x;\n",
    "        *z = 5;\n",
    "}\n",
    "\"\"\"\n",
    "\n",
    "c_header = \"\"\"\n",
    "void test_entry(int x, int *y, int *z);\n",
    "\"\"\"\n",
    "\n",
    "with open(\"test.c\", \"w\") as f:\n",
    "    f.write(c_source)\n",
    "    \n",
    "with open(\"test.h\", \"w\") as f:\n",
    "    f.write(c_header)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d87a5fa8",
   "metadata": {},
   "source": [
    "2. Compile the C source into a shared library:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "id": "507b5d4f",
   "metadata": {},
   "outputs": [],
   "source": [
    "!gcc -shared -fPIC -o libtest.so test.c"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b3d74cb2",
   "metadata": {},
   "source": [
    "### Procedure\n",
    "\n",
    "1. Construct a task that interfaces with the compiled function using a Covalent lepton object:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "id": "d23fe762",
   "metadata": {},
   "outputs": [],
   "source": [
    "import covalent as ct\n",
    "from ctypes import POINTER, c_int32\n",
    "import os\n",
    "\n",
    "library_path = os.path.join(os.getcwd(),\"libtest.so\")\n",
    "\n",
    "task = ct.Lepton(\n",
    "    language = \"C\",\n",
    "    library_name = library_path,\n",
    "    function_name = \"test_entry\",\n",
    "    argtypes = [                     # Type conversion info required by the lepton object\n",
    "        (c_int32, ct.Lepton.INPUT),\n",
    "        (POINTER(c_int32), ct.Lepton.INPUT_OUTPUT),\n",
    "        (POINTER(c_int32), ct.Lepton.OUTPUT)\n",
    "    ]\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d14e3ce4",
   "metadata": {},
   "source": [
    "2. Use the lepton in the context of a lattice:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "id": "7826e8cd",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(3, 5)\n"
     ]
    }
   ],
   "source": [
    "@ct.lattice\n",
    "def workflow(x: int, y: int) -> int:\n",
    "    return task(x, y)\n",
    "\n",
    "dispatch_id = ct.dispatch(workflow)(1, 2)\n",
    "result = ct.get_result(dispatch_id, wait=True)\n",
    "print(result.result)"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "id": "bd101ade",
   "metadata": {},
   "source": [
    "Note that the return values consist of input-output and output-only variables. Output-only variables can only be scalars, since there is no way to to determine an output-only variable's array size. To return an array, declare it as an input-output variable and initialize it appropriately before passing it to the lepton.\n",
    "\n",
    "### See Also\n",
    "\n",
    "[Constructing a Lepton](./construct_lepton.ipynb)\n",
    "\n",
    "[Covalent API: Lepton](https://covalent.readthedocs.io/en/latest/api/leptons.html)\n",
    "\n",
    "[Constructing Tasks from Bash Scripts](./construct_bash_task.ipynb)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.15"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
